import {
    Component,
    ElementRef,
    HostListener,
    Input,
    OnChanges,
    OnDestroy,
    OnInit,
} from '@angular/core';
import {HttpService} from '@kylin/http';
import {bbox as bboxStrategy} from 'ol/loadingstrategy.js';
import {NzMessageService} from 'ng-zorro-antd';
import WKT from 'ol/format/WKT';
import {LayersPanelService} from '../layers-panel/layers-panel.service';
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import {click, pointerMove, altKeyOnly} from 'ol/events/condition.js';
import {getCenter} from 'ol/extent';
import {GeoJSON} from 'ol/format';
import Select from 'ol/interaction/Select';

@Component({
    selector: 'kylin-features-panel',
    templateUrl: './features-panel.component.html',
    styleUrls: ['./features-panel.component.less']
})
export class FeaturesPanelComponent implements OnInit, OnDestroy {

    layerId: string;
    layerName: string;
    layerType: string;
    openStatus: boolean;
    wmsUrl: string;

    @Input() set layer(val: any) {
        if (val) {
            this.layerId = val.layerId;
            this.layerName = val.layerName;
        }
    };

    features = new Array<any>();
    heads: string[];
    size = 10;
    current = 1;
    total: number;
    editing = false;
    getLoading = false;
    editFid: string | null;
    editedFeatures = new Array<any>(); // 修改过的内容
    currentTrEle: any;
    currentFeature: any;
    filterVisible = false;
    sqlString: string; // 逻辑运算器操作结果
    sortName: string;
    sortValue: string;
    crtSelFeatureLayer: any;
    selFeatureFid: any;
    selectedFid: any;
    @Input() map: Map;
    hiddenLayer: any; // 图层的矢量瓦片图层，透明度为0，用于计算点击点是否为feature
    saveLoading: boolean;
    selectInteraction: any;


    @HostListener('window:click', ['$event'])
    handleClick(e: MouseEvent): void {
        // TODO editedFeatures 添加当前修改后的内容
        if (this.editFid && this.currentTrEle && this.currentTrEle !== e.target && !this.currentTrEle.contains(e.target)) {
            this.editFid = null;
            this.addFeature({...this.currentFeature});
            this.currentFeature = null;
        }
    }

    constructor(private http: HttpService, private message: NzMessageService, private layersPanelService: LayersPanelService) {
    }

    ngOnInit() {
        if (this.layerId) {
            this.getFeatures();
            this.getWMSURL();
        } else {
            this.layerId = 'ec996402f6874991a16d3e2d9e57b6de';
            this.getFeatures();
            this.getWMSURL();
        }
    }

    getFeatures(params?: any) {
        this.getLoading = true;
        this.http.get('/layer/shpPropertyAll', {
            layerId: this.layerId,
            current: this.current,
            size: this.size,
            sql: this.sqlString || '',
            orderBy: this.sortName || '',
            order: this.sortValue || ''
        } as any).then(rep => {
            this.getLoading = false;
            if (rep.resp_code === '10000') {
                this.features = rep.data.records;
                if (this.features && this.features.length) {
                    this.heads = Object.keys(this.features[0]).filter(item => {
                        return ['the_geom', 'fid'].indexOf(item) === -1;
                    });
                    this.features = this.features.map(item => {
                        let tmp = {};
                        Object.keys(item).map(tem => {
                            item[tem] = (item[tem] || item[tem] === 0 ? item[tem] : '') + '';
                            tmp = item;
                        });
                        return tmp;
                    });
                    if (this.features[0]['fid']) {
                        this.heads = ['fid'].concat(this.heads as any);
                    }
                    this.current = rep.data.current;
                    this.size = rep.data.size;
                    this.total = rep.data.total;
                }
            } else {
                this.message.error('获取数据失败' + rep.resp_msg);
            }
        });
    }

    modifyFeatureProp() {
        if (this.editedFeatures.length === 0) {
            this.message.warning('暂无修改记录');
        }
        const params = new Array<any>();
        this.editedFeatures.forEach(value => {
            params.push(value);
        });
        this.saveLoading = true;
        this.http.put('/layer/shpProperty', {layerId: this.layerId, params}).then(rep => {
            this.saveLoading = false;
            this.editedFeatures = new Array<any>();
            this.editing = false;
            if (rep.resp_code === '10000') {
                this.message.success('修改数据成功');
            } else {
                this.message.error('修改数据失败' + rep.resp_msg);
            }
        })
    }

    selectFeature(feature: any) {
        // TODO 选中feature
        this.selectedFid = feature.fid;
        this.http.get('/layer/shpProperty', {
            layerId: this.layerId,
            fid: feature.fid
        }).then(rep => {
            if (rep.resp_code === '10000') {
                const olFeature = new WKT().readFeature(rep.data['the_geom']);
                const vectorSource = new VectorSource({
                    features: [olFeature]
                });
                const vectorLayer = new VectorLayer({
                    source: vectorSource
                });
                if (this.crtSelFeatureLayer) {
                    this.map.removeLayer(this.crtSelFeatureLayer);
                }
                this.crtSelFeatureLayer = vectorLayer;
                this.map.addLayer(vectorLayer);
                const extent = olFeature.getGeometry().getExtent();
                // TODO 编译后有警告，待处理
                const center = getCenter(extent);
                this.map.getView().setCenter(center);
                // TODO 选中要素的样式优化，取要素颜色的反色填充
                this.selectInteraction.getFeatures().clear();
                this.selectInteraction.getFeatures().push(olFeature)
            }
        });

    }

    addFeature(feature: any) {
        let repeat = false;
        this.editedFeatures = this.editedFeatures.map(item => {
            if (item.fid === feature.fid) {
                repeat = true;
                item = feature;
            }
            return item;
        });
        if (!repeat) {
            this.editedFeatures.push({...feature})
        }
    }

    startEdit(feature, event: MouseEvent, rowElement) {
        event.preventDefault();
        event.stopPropagation();
        if (this.editing) {
            if (this.editFid) {
                this.addFeature({...this.currentFeature});
            }
            this.editFid = feature.fid;
            this.currentTrEle = rowElement;
            this.currentFeature = feature;
        }
    }

    enterEditing() {
        this.editing = true;
    }

    saveModify() {
        this.editFid = null;
        this.currentTrEle = null;
        if (this.currentFeature) {
            this.addFeature({...this.currentFeature});
        }
        this.modifyFeatureProp();
    }

    openFilter() {
        this.filterVisible = true;
    }

    reGetFeatures(sql) {
        this.sqlString = sql;
        this.getFeatures({
            sql,
            current: 1,
            size: 10
        });
    }

    sortFeatures(sort: { key: string; value: string }) {
        const orderMap = {
            ascend: 'asc',
            descend: 'desc',
        };
        this.sortName = sort.key;
        this.sortValue = orderMap[sort.value] || '';
        this.getFeatures();
    }

    genWFSUrl(extent, httpHead, featureType, layerName) {
        return httpHead + featureType + '/wfs?service=WFS&version=1.1.0&request=GetFeature&typename=' + layerName + '&maxFeatures=99999999&outputFormat=application/json&srsname=EPSG:3857&bbox=' + extent.join(',') + ',EPSG:3857';
    }

    getWMSURL() {
        this.http.get(`/layer/${this.layerId}`).then(rep => {
            if (rep.resp_code === '10000') {
                this.wmsUrl = rep.data[0].geoserverUrl;
                const featureType = this.wmsUrl.match(/geoserver\/([a-zA-Z]+)\//)[1];
                const layerName = this.wmsUrl.match(/layers=([\w|:]+)&/)[1];
                // 接收到的wmsUrl格式如下
                // "http://47.92.200.205:18080/geoserver/pointMap/wms?service=WMS&version=1.1.0&request=GetMap&layers=pointMap:1567675466353&styles=&bbox=122.958611,48.040277,124.113888,48.701666&width=768&height=437&srs=EPSG:4326"
                const httpHead = this.wmsUrl.match(/^(.+geoserver\/)/)[1];
                const vectorSource = new VectorSource({
                    format: new GeoJSON(),
                    url: (extent) => { // 注意: 通过wfs 加载geojson的时候，如果url没有extent这一步处理，那么页面openlayer加载不到地图，不显示
                        return this.genWFSUrl(extent, httpHead, featureType, layerName);
                    },
                    strategy: bboxStrategy
                });
                const vectorLayer = new VectorLayer({
                    source: vectorSource,
                    opacity: 0
                });
                this.hiddenLayer = vectorLayer;
                const selector = new Select({
                    condition: click
                } as any);
                this.map.addLayer(this.hiddenLayer);
                this.map.addInteraction(selector);
                this.selectInteraction = selector;
                selector.on('select', (evt) => {
                    const feature = evt.selected[0];
                    this.map.removeLayer(this.crtSelFeatureLayer);
                    if (feature) {
                        const selectedFid = feature.get('fid');
                        // this.selectFeature(feature.getProperties());
                        this.setSelState(selectedFid);
                    }
                });
            }
        })
    }

    setSelState(selectedFid: any) {
        this.http.get('/layer/shpProperty', {
            layerId: this.layerId,
            fid: selectedFid,
        }).then(rep => {
            if (rep.resp_code === '10000') {
                this.total = 1;
                this.features = [rep.data];
            } else {
                this.message.error('获取数据失败' + rep.resp_msg);
            }
        });
    }

    ngOnDestroy(): void {
        if (this.crtSelFeatureLayer) {
            this.map.removeLayer(this.crtSelFeatureLayer);
        }
        if (this.hiddenLayer) {
            this.map.removeLayer(this.hiddenLayer);
        }
        if (this.selectInteraction) {
            this.map.removeInteraction(this.selectInteraction);
        }
    }
}
